package com.zysc.processflow.common.polygon;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Polygon {
    private List<Position> polygonPoints;
    private Position[] miniRectangle;

    public Polygon(List<Position> polygonPoints){
        this.polygonPoints = polygonPoints;
    }


    /**
     * 获取最小外接矩形，第一个点是最小点，第二个点为最大点
     * @return
     */
    public Position[] GetMiniRectangle(){
        if(miniRectangle == null) {
            miniRectangle = new Position[2];
            miniRectangle[0] = new Position();
            miniRectangle[0].setX(0.0);
            miniRectangle[0].setY(0.0);
            miniRectangle[1] = new Position();
            miniRectangle[1].setX(0.0);
            miniRectangle[1].setY(0.0);

            miniRectangle[0].setX(Collections.min(polygonPoints.stream().map(Position::getX).collect(Collectors.toList())));
            miniRectangle[0].setY(Collections.min(polygonPoints.stream().map(Position::getY).collect(Collectors.toList())));
            miniRectangle[1].setX(Collections.max(polygonPoints.stream().map(Position::getX).collect(Collectors.toList())));
            miniRectangle[1].setY(Collections.max(polygonPoints.stream().map(Position::getY).collect(Collectors.toList())));
        }
        return miniRectangle;
    }

    /**
     * 判断点是否在多边形内部
     * @param checkPoint
     * @return
     */
    public boolean IsInPolygon(Position checkPoint) {
        // 判断点是否在最小外接矩形的外面
        Position[] miniRectangle = this.GetMiniRectangle();
        if(checkPoint.getX() < miniRectangle[0].getX() || checkPoint.getX() > miniRectangle[1].getX()
        || checkPoint.getY() < miniRectangle[0].getY() || checkPoint.getY() > miniRectangle[1].getY()){
            return false;
        }
        int counter = 0;
        int i;
        double xinters;
        Position p1, p2;
        int pointCount = polygonPoints.size();
        p1 = (Position) polygonPoints.get(0);
        for (i = 1; i <= pointCount; i++) {
            p2 = polygonPoints.get(i % pointCount);
            //校验点的Y大于线段端点的最小Y
            if (checkPoint.getY() > Math.min(p1.getY(), p2.getY()) && checkPoint.getY() <= Math.max(p1.getY(), p2.getY()))//校验点的Y小于线段端点的最大Y
            {
                if (checkPoint.getX() <= Math.max(p1.getX(), p2.getX()))//校验点的X小于等于线段端点的最大X(使用校验点的左射线判断).
                {
                    if (p1.getY() != p2.getY())//线段不平行于X轴
                    {
                        xinters = (checkPoint.getY() - p1.getY()) * (p2.getX() - p1.getX()) / (p2.getY() - p1.getY()) + p1.getX();
                        if (p1.getX() == p2.getX() || checkPoint.getX() <= xinters) {
                            counter++;
                        }
                    }
                }
            }
            p1 = p2;
        }

        if (counter % 2 == 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 获取在多边形内部的点集合
     * @param checkPoints
     * @return
     */
    public List<Position> InPolygonPoints(List<Position> checkPoints){
        List<Position> inPositions = new ArrayList<>();
        for (Position p : checkPoints){
            if(IsInPolygon(p)){
                inPositions.add(p);
            }
        }
        return inPositions;
    }
}


